import React, { useRef } from 'react';
import { useDrop, useDrag } from 'react-dnd';
import { Icon, Popconfirm } from 'antd';
import throttle from 'lodash/throttle';
import classNames from 'classnames';
import { connect } from 'dva';
import { closest } from '@/utils/utils';
import { getLevel } from './utils';
import { itemTypes } from './types';
import styles from '../styles.less';

const throttledMoveItem = throttle(
  (fuc, dragLevel, hoverLevel, item, box, msg) => {
    fuc(dragLevel, hoverLevel, item, box, msg);
  },
  300,
  {
    trailing: false,
    leading: true,
  }
);

const DndItem = ({
  data,
  type,
  level,
  children,
  dispatch,
  formSchema,
  current,
  moveItem,
  className = '',
  style = {},
}) => {
  const ref = useRef(null);
  const box = { id: data.id, componentType: data.componentType, type, level };

  const editIt = (e, item, current = {}) => {
    e.preventDefault();
    e.stopPropagation();

    if (current.__id === item.__id) {
      return;
    }
    // BUG: 防止formily在校验错误时 自动追加pattern属性
    // const { rules = [] } = item;
    // const newRules = [];
    // rules.forEach(obj => {
    //   if (obj.format || obj.required) {
    //     const { pattern, ...rest } = obj;
    //     newRules.push(rest);
    //     return;
    //   }
    //   newRules.push(obj);
    // });

    dispatch({
      type: 'formDesigner/setCurrent',
      payload: { ...item, level },
    });
  };

  const deleteIt = (e, level) => {
    e.preventDefault();
    e.stopPropagation();
    dispatch({
      type: 'formDesigner/removeItem',
      payload: {
        level,
      },
    });
  };

  const toggleSelect = (e, item) => {
    e.preventDefault();
    e.stopPropagation();
    if (item.__id === current.__id) {
      dispatch({
        type: 'formDesigner/setCurrent',
        payload: {},
      });
    } else {
      editIt(e, item);
    }
  };

  const [{ isDragging }, drag] = useDrag({
    // item 中包含 index 属性，则在 drop 组件 hover 和 drop 是可以根据第一个参数获取到 index 值
    item: box,
    collect: monitor => ({
      isDragging: monitor.isDragging(),
    }),
    begin(monitor) {
      // __id= 'holder' 表示是占位的
      // const isExisted = getLevel(formSchema, { __id: 'holder' }) !== -1;

      // // 拖拽开始时，向 树的后面插入一个占位的元素，如果占位元素已经存在，不再重复插入
      // if (!isExisted && box.componentType === 'Card') {
      //   dispatch({
      //     type: 'formDesigner/addItem',
      //     payload: {
      //       level: `${formSchema.length}`,
      //       item: {
      //         'componentType': box.componentType,
      //         __id: 'holder',
      //         label,
      //         name: null,
      //         properties: [],
      //       },
      //     },
      //   });
      // }
      return box;
    },
    end(_, monitor) {
      // console.log('isDragging', isDragging);
    },
  });

  const [{ canDrop, isOver }, drop] = useDrop({
    accept: [itemTypes.bowl, itemTypes.food, itemTypes.block, itemTypes.staticBlock],
    // drag组件可以被放置到当前drop组件时触发的事件

    /**
     * drag 组件在 drop 组件上方 hover 时触发
     * @param {objcet} item 表示当前被拖拽的组件属性
     * @param {*} monitor
     */
    hover(item, monitor) {
      if (!ref.current) {
        return;
      }

      const holderLevel = getLevel(formSchema, { __id: 'holder' });
      const dragLevel = item.level;
      const hoverLevel = level;
      // const dragParentLevel =
      //   dragLevel !== undefined ? dropRight(`${dragLevel}`.split('-')).join('-') : undefined;
      // const hoverParentLevel =
      //   hoverLevel !== undefined ? dropRight(`${hoverLevel}`.split('-')).join('-') : undefined;

      // 确定屏幕上矩形范围
      const hoverBoundingRect = ref.current.getBoundingClientRect();

      // 获取中点垂直坐标
      const hoverMiddleY = (hoverBoundingRect.bottom - hoverBoundingRect.top) / 2;

      // 确定鼠标位置
      const clientOffset = monitor.getClientOffset();

      // 获取距顶部距离
      const hoverClientY = clientOffset.y - hoverBoundingRect.top;

      // 1、从左侧拖拽组件进入画布，因为只有那个时候dragLevel 等于 undefined
      if (dragLevel === undefined) {
        // 1.1、拖拽Left组件中的bowl类型
        if (item.type === itemTypes.bowl) {
          // hover food类型时 一律不处理
          if (type === itemTypes.food) {
            return;
          }
          // hover在holder元素上方
          if (data.__id === 'holder') {
            return;
          }
          if (type === itemTypes.bowl) {
            // 拖拽的元素 从hover元素的上方向下经过， 未超过hover元素高度一半， 并且holder 已经在 hover上方时
            if (
              hoverClientY < hoverMiddleY &&
              parseInt(getLevel(formSchema, { __id: 'holder' }), 10) === parseInt(level, 10) - 1
            ) {
              return;
            }

            // 拖拽的元素 从hover元素的下方向上经过， 未超过hover元素高度一半，并且holder 已经在 hover下方时
            if (
              hoverClientY > hoverMiddleY &&
              parseInt(getLevel(formSchema, { __id: 'holder' }), 10) === parseInt(level, 10) + 1
            ) {
              return;
            }

            // 从上往下 或 从下往上  超过一半  执行 move 回调函数
            moveItem(dragLevel, hoverLevel, item, box, 'left bowl hover bowl');
          }

          if (type === itemTypes.food) {
            return;
          }
        }

        // 1.2、拖拽Left组件中的food类型 ok
        if (item.type === itemTypes.food) {
          // hover在bowl上面
          if (type === itemTypes.bowl) {
            // holder元素已经在当前hover的容器内
            if (parseInt(`${holderLevel}`.split('-')[0], 10) === parseInt(hoverLevel, 10)) {
              return;
            }

            // 拖拽的元素 从hover元素的上方向下经过， 未超过hover元素高度一半， 并且holder 已经在 hover上方时
            if (dragLevel < hoverLevel && hoverClientY < hoverMiddleY) {
              return;
            }

            // 拖拽的元素 从hover元素的下方向上经过， 未超过hover元素高度一半，并且holder 已经在 hover下方时
            if (dragLevel > hoverLevel && hoverClientY > hoverMiddleY) {
              return;
            }

            // 从上往下 或 从下往上  超过一半  执行 move 回调函数
            moveItem(dragLevel, hoverLevel, item, box, 'left food hover bowl');
          }

          // hover在food上面
          // TODO: 从Left拖拽的food hover在food上 如果holder没在hover的food所在的容器，则移动holder
          // if (type === itemTypes.food) {
          //   console.log('food hover food');
          //   // holder元素已经在当前hover的容器内
          //   if (parseInt(`${holderLevel}`.split('-')[0], 10) === parseInt(hoverLevel, 10)) {
          //     return;
          //   }
          //   moveItem(dragLevel, hoverLevel, item, box);
          // }
        }
      } else if ([itemTypes.bowl, itemTypes.block, itemTypes.staticBlock].includes(item.type)) {
        // 2.1、拖拽的是canvas中的bowl组件

        // hover food类型时 一律不处理
        if (type === itemTypes.food) {
          return;
        }

        // 拖拽元素下标与鼠标悬浮元素下标一致时，不进行操作
        if (dragLevel === hoverLevel) {
          return;
        }

        // 拖拽的元素 从hover元素的上方向下经过， 未超过hover元素高度一半， 并且holder 已经在 hover上方时
        if (dragLevel < hoverLevel && hoverClientY < hoverMiddleY) {
          return;
        }

        // 拖拽的元素 从hover元素的下方向上经过， 未超过hover元素高度一半，并且holder 已经在 hover下方时
        if (dragLevel > hoverLevel && hoverClientY > hoverMiddleY) {
          return;
        }

        // 从上往下 或 从下往上  超过一半  执行 move 回调函数
        moveItem(dragLevel, hoverLevel, item, box, 'canvas bowl hover bowl');

        item.level = hoverLevel;
      } else if (item.type === itemTypes.food) {
        // 2.2、拖拽的是canvas中的food组件
        // BUG: food元素能够在card直接拖拽

        // hover的是当前的bowl， 一律不处理
        if (
          type === itemTypes.bowl &&
          parseInt(`${level}`.split('-')[0], 10) === parseInt(hoverLevel, 10)
        ) {
          return;
        }

        // hover的不是当前的bowl中的food，一律不处理
        if (
          type === itemTypes.food &&
          parseInt(`${dragLevel}`.split('-')[0], 10) !== parseInt(hoverLevel, 10)
        ) {
          return;
        }

        // 拖拽元素下标与鼠标悬浮元素下标一致时(表示hover的是自己的holder镜像)，不进行操作
        if (dragLevel === hoverLevel) {
          return;
        }

        // 拖拽的元素 从hover元素的上方向下经过， 未超过hover元素高度一半， 并且holder 已经在 hover上方时
        // if (dragLevel < hoverLevel && hoverClientY < hoverMiddleY) {
        //   return;
        // }

        // // 拖拽的元素 从hover元素的下方向上经过， 未超过hover元素高度一半，并且holder 已经在 hover下方时
        // if (dragLevel > hoverLevel && hoverClientY > hoverMiddleY) {
        //   return;
        // }

        // 必须节流处理，否则遇到hover的food跨度很长时，两个food位置对调之后，还会继续触发moveItem
        throttledMoveItem(moveItem, dragLevel, hoverLevel, item, box, 'canvas food hover bowl');

        item.level = hoverLevel;
      }
    },
    collect: monitor => ({
      isOver: monitor.isOver(),
      canDrop: monitor.canDrop(),
    }),
  });

  drag(drop(ref));

  return (
    <div
      ref={ref}
      id={data.__id}
      onClick={e => editIt(e, data, current)}
      style={style}
      className={classNames(
        styles.editItem,
        [
          {
            selected: `${current.__id}` === `${data.__id}`,
            // [styles.bowl]: type === itemTypes.bowl,
            // [styles.food]: type === itemTypes.food,
          },
        ],
        className
      )}
    >
      <div className={styles.actionBar}>
        <div className={styles.action}>
          {/* form加了随机key之后 导致 popconfirm无法触发 */}
          <Popconfirm
            title="确定要删除吗？"
            onConfirm={e => deleteIt(e, level)}
            getPopupContainer={() => closest(ref.current, '.media-box')}
          >
            <Icon type="close-circle" />
          </Popconfirm>
        </div>
      </div>
      {isDragging ? <div className={classNames(styles.mask, styles.move)} /> : null}
      {data.__id === 'holder' ? <div className={classNames(styles.mask, styles.holder)} /> : null}
      {children}
    </div>
  );
};

export default connect(({ formDesigner }) => ({
  formSchema: formDesigner.formSchema,
  current: formDesigner.current,
}))(DndItem);
